package the.broccoli.ac.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.wisteria.framework.util.TreeUtils;
import org.wisteria.framework.web.BusinessException;
import org.wisteria.framework.web.QueryResult;
import org.wisteria.framework.web.mvc.constant.WebConsts;
import org.wisteria.framework.web.mvc.dto.ConditionDTO;
import org.wisteria.framework.web.mvc.service.AbstractSuperService;
import the.broccoli.ac.constant.ResType;
import the.broccoli.ac.dto.ResTree;
import the.broccoli.ac.entity.App;
import the.broccoli.ac.entity.Res;
import the.broccoli.ac.mapper.ResMapper;
import the.broccoli.ac.service.IAppService;
import the.broccoli.ac.service.IResService;
import the.broccoli.ac.vo.AppVO;
import the.broccoli.ac.dto.ResCondition;
import the.broccoli.setting.service.ILanguageService;

import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 资源（目录、菜单，按钮、页面） 服务实现类
 * </p>
 *
 * @author lei.liu
 * @since 2020-04-07
 */
@Service
public class ResServiceImpl extends AbstractSuperService<ResMapper, Res> implements IResService {

    @Autowired
    private IAppService appService;

    @Autowired
    private ILanguageService languageService;

    /**
     * 分页查询
     *
     * @param condition 查询条件
     * @param pageNum   页码
     * @param pageSize  每页条数
     * @return
     */
    @Override
    public QueryResult pageList(ConditionDTO condition, Integer pageNum, Integer pageSize) {
        QueryResult queryResult = super.pageList(condition, pageNum, pageSize);
        if (!CollectionUtils.isEmpty(queryResult.getItems())) {
            for (Res res : (List<Res>)queryResult.getItems()) {
                Locale locale = LocaleContextHolder.getLocale();
                String lang = locale.getLanguage();
                if (Locale.US.getLanguage().equals(lang)) {
                    res.setResName(res.getNameUs());
                } else {
                    res.setResName(res.getNameCn());
                }
            }
        }
        return queryResult;
    }

    /**
     * 删除数据并记录操作信息
     *
     * @param ids          ID集合
     * @param modifiedId   操作人ID
     * @param modifiedName 操作人名称
     */
    @Transactional
    @Override
    public boolean removeByIds(Collection<? extends Serializable> ids, String modifiedId, String modifiedName) {
        if (CollectionUtils.isEmpty(ids)) {
            return true;
        }
        for (Serializable id :ids) {
            Res res = getById(id);
            if (res != null) {
                languageService.removeByCode("res", res.getResCode(), modifiedId, modifiedName);
            }
        }
        return super.removeByIds(ids, modifiedId, modifiedName);
    }

    @Transactional
    @Override
    public boolean updateById(Res entity) {
        languageService.save("res", entity.getResCode(), entity.getResName(), entity.getModifiedId(), entity.getModifiedName());
        return super.updateById(entity);
    }

    @Transactional
    @Override
    public boolean save(Res entity) {
        if (StringUtils.hasText(entity.getResCode()) ) {
            ResCondition condition = new ResCondition();
            condition.setAppIdList(Arrays.asList(entity.getAppId()));
            condition.setResCode(entity.getResCode());
            if (!CollectionUtils.isEmpty(listByCondition(condition))) {
                throw BusinessException.withErrorCode("res.code.is.exists");
            }
        }
        languageService.save("res", entity.getResCode(), entity.getResName(), entity.getCreatedId(), entity.getCreatedName());
        return super.save(entity);
    }

    /**
     * 获取应用的所有资源信息
     * @param appIdList     应用ID
     * @return
     */
    @Override
    public List<Res> listByAppIdBatch(List<Integer> appIdList) {
        return baseMapper.selectList(new LambdaQueryWrapper<Res>()
                .in(Res::getAppId, appIdList)
        );
    }

    @Override
    public List<ResTree> getAppResTree(List<Integer> appIdList, List<ResType> resTypeList) {
        AppVO appCondition = new AppVO();
        appCondition.setAppIdList(appIdList);
        List<App> appList = appService.listByCondition(appCondition);
        if (CollectionUtils.isEmpty(appList)) {
            return null;
        }

        List<Res> resList = new ArrayList<>();
        Res res = null;
        for (App app : appList) {
            res = new Res();
            res.setResId(WebConsts.ROOT);
            res.setResName(app.getAppName());
            res.setParentId("0");
            resList.add(res);
        }

        List<Res> _resList = getResListByAppIdList(appIdList, resTypeList);
        if (!CollectionUtils.isEmpty(_resList)) {
            resList.addAll(_resList);
        }
        return buildTree(resList, "0");
    }

    /**
     * 获取资源树
     *
     * @param appId 应用ID
     * @return
     */
    @Override
    public List<ResTree> getTree(Integer appId, List<ResType> resTypeList) {
        return getTreeForAppId(Arrays.asList(appId), resTypeList);
    }

    @Override
    public List<ResTree> getTreeForAppId(List<Integer> appIdList, List<ResType> resTypeList) {
        return buildTree(getResListByAppIdList(appIdList, resTypeList));
    }

    @Override
    public List<ResTree> getTree(List<String> resIdList, List<ResType> resTypeList) {
        return buildTree(getResListByResIdList(resIdList, resTypeList));
    }

    private List<ResTree> buildTree(List<Res> resList) {
        return buildTree(resList, WebConsts.ROOT);
    }

    private List<ResTree> buildTree(List<Res> resList, String root) {
        if (CollectionUtils.isEmpty(resList)) {
            return new ArrayList<>();
        }

        List<ResTree> treeList = resList.stream()
                .filter(entity -> !entity.getResId().equals(entity.getParentId()))
                .map(entity -> {
                    ResTree node = new ResTree();
                    node.setId(entity.getResId());
                    node.setParentId(entity.getParentId());
                    node.setName(entity.getResName());
                    node.setUrl(entity.getUrl());
                    node.setIcon(entity.getIcon());
                    return node;
                }).collect(Collectors.toList());
        return TreeUtils.bulid(treeList, root);
    }

    private List<Res> getResListByAppIdList(List<Integer> appIdList, List<ResType> resTypeList) {
        ResCondition resCondition = new ResCondition();
        resCondition.setAppIdList(appIdList);
        if (!CollectionUtils.isEmpty(resTypeList)) {
            List<String> resTypeStrList = new ArrayList<>();
            for (ResType resType : resTypeList) {
                resTypeStrList.add(resType.getValue());
            }
            resCondition.setResTypeList(resTypeStrList);
        }
        return super.listByCondition(resCondition);
    }

    private List<Res> getResListByResIdList(List<String> appIdList, List<ResType> resTypeList) {
        if (CollectionUtils.isEmpty(appIdList)) {
            return null;
        }

        ResCondition resCondition = new ResCondition();
        resCondition.setResIdList(appIdList);
        if (!CollectionUtils.isEmpty(resTypeList)) {
            List<String> resTypeStrList = new ArrayList<>();
            for (ResType resType : resTypeList) {
                resTypeStrList.add(resType.getValue());
            }
            resCondition.setResTypeList(resTypeStrList);
        }
        return super.listByCondition(resCondition);
    }
}
